/*
 * Copyright (c) 2006 Rick Mugridge, www.RimuResearch.com
 * Released under the terms of the GNU General Public License version 2 or later.
 * Written: 16/12/2006
*/

package com.nhncorp.ntaf;

import fit.Fixture;
import fit.FlowState;
import fit.Parse;
import fit.RunningState;
import fitlibrary.suite.FlowControl;
import fitlibrary.table.Table;
import fitlibrary.table.Tables;
import fitlibrary.utility.TableListener;
import fitlibrary.utility.TestResults;

public class NtafInFlowPageRunner {
	private NtafDoEvaluator doEvaluator;
	boolean abandoned = false;
	private boolean stopOnError = false;
	private int stateCount = 0;
	private int runtableIndex;
	private int endTablePosition;
	static NtafInfo ntafInfo = new NtafInfo();

	public NtafInFlowPageRunner(NtafDoEvaluator doEvaluator, boolean abandoned) {
		this.doEvaluator = doEvaluator;
		this.abandoned = abandoned;
		doEvaluator.registerFlowControl(new FlowControl() {
			public void abandon() {
				NtafInFlowPageRunner.this.abandoned = true;
			}

			public void setStopOnError(boolean stopOnError) {
			}
		});
	}

	public void printHelp(String keyword, Parse parse) {
		try {
			String resultStr = NtafFixture.parsingXML("FlowFixture", keyword);
			if (resultStr.equals("")) {
				resultStr = "Can't find help comment in XML";
			}
			parse.addToBody("<hr>" + "Attribute List" + "<br>" + Fixture.label(resultStr));
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public int getEndTableIndex(Tables tables, int from) {
		int size = tables.size();
		int i, j;

		for (i = from; i < size; i++) {
			Table table = tables.table(i);
			String keywordname = table.row(0).text(0);

			if (NtafInfo.getKeywords().contains(keywordname)) {
				int staeAccumulate = 0;
				if (ntafInfo.isStartKeyword(keywordname)) {

					++staeAccumulate;
					for (j = i + 1; j < size; j++) {
						Table nextTable = tables.table(j);
						String nextKeywordname = nextTable.row(0).text(0);

						if (keywordname.equals(nextKeywordname)) {
							++staeAccumulate;
						} else {
							if (ntafInfo.findEndKeyword(keywordname, nextKeywordname)) {
								--staeAccumulate;

								if (0 == staeAccumulate) {
									return j;
								}
							}
						}
					}
				}
			}
		}

		return size;
	}

	protected boolean isTimeout(RunningState state) {
		return null != state && FlowState.TIMEOUT == state.getRunState();
	}

	public int runTables(Tables tables, int from, TableListener tableListener, boolean runByBlock, RunningState state) {
		TestResults testResults = tableListener.getTestResults();
		int tableSize = tables.size();
		int innerTableIndex;

		endTablePosition = tableSize;

		for (runtableIndex = from; runtableIndex < tableSize; runtableIndex++) {

			if (isTimeout(state)) {
				break;
			}

			Table table = tables.table(runtableIndex);
			String keywordname = table.row(0).text(0);

			if (NtafInfo.getKeywords().contains(keywordname)) {

				boolean help = isHelp(table);
				ignoreCellIfRequired(testResults, table);

				stateCount = 0;
				if (ntafInfo.isStartKeyword(keywordname)) {
					++stateCount;

					ntafInfo.addState(keywordname);
					parseCommandIfExist(table, keywordname);

					innerTableIndex = calculateState(tables, testResults, runtableIndex, keywordname);
					runNestedTables(tables, tableListener, state, innerTableIndex, table, keywordname,
						help);

					if (runByBlock)
						return endTablePosition;
				} else {
					runNonPairKeywordAndFixture(tableListener, table, keywordname);
				}

			} else {
				runOtherTables(tableListener, testResults, table);
			}
		}
		return endTablePosition;
	}

	private void runNestedTables(Tables tables, TableListener tableListener, RunningState state,
			int innerTableIndex, Table table, String keywordname, boolean help) {
		
		TestResults testResults = tableListener.getTestResults();
		
		if (isIgnore(testResults, stateCount)) {
			ignoreCellIfRequired(testResults, table);
		} else {
			if (help) {
				printHelp(keywordname, table.row(0).cell(1).parse);
			} else {
				doEvaluator.interpretInnerTables(tables, runtableIndex + 1, innerTableIndex, tableListener, state);
				endTablePosition = runtableIndex = innerTableIndex;
			}
		}
	}

	private int calculateState(Tables tables, TestResults testResults, int tableIndex, String keywordname) {
		int tableSize = tables.size();
		int innerTableIndex;

		for (innerTableIndex = tableIndex + 1; innerTableIndex < tableSize; innerTableIndex++) {
			Table nextTable = tables.table(innerTableIndex);
			String nextKeywordname = nextTable.row(0).text(0);

			if (keywordname.equals(nextKeywordname)) {
				++stateCount;
			} else {
				if (ntafInfo.findEndKeyword(keywordname, nextKeywordname)) {
					ignoreCellIfRequired(testResults, nextTable);
					--stateCount;

					if (0 == stateCount) {
						break;
					}
				}
			}
		}

		return innerTableIndex;
	}
	
	private boolean isError(TestResults testResults) {
		return abandoned || (stopOnError && testResults.problems());
	}

	private boolean isIgnore(TestResults testResults, int staeAccumulate) {
		return isError(testResults) || 0 != staeAccumulate;
	}

	private void runOtherTables(TableListener tableListener, TestResults testResults, Table table) {
		if (isError(testResults))
			ignoreCellIfRequired(testResults, table);
		else {
			doEvaluator.interpretWholeTable(table, tableListener);
		}
	}

	private void runNonPairKeywordAndFixture(TableListener tableListener, Table table, String keywordname) {
		if (keywordname.equals("command_log") && table.row(0).cellExists(1)) {
			ntafInfo.printLog(table.row(0).text(1));
		} else if (keywordname.equals("command_var") && table.row(0).cellExists(1)) {
			table.row(0).addCell().setText(ntafInfo.replaceSymbol(table.row(0).text(1)));
		} else {
			doEvaluator.interpretWholeTable(table, tableListener);
		}
	}

	private void parseCommandIfExist(Table table, String keywordname) {
		if (table.row(0).cellExists(1))
			ntafInfo.parseCommand(keywordname, table.row(0).text(1));
	}

	private void ignoreCellIfRequired(TestResults testResults, Table table) {
		if (false == table.row(0).cell(0).isIgnored())
			table.row(0).cell(0).ignore(testResults);
	}

	protected boolean isHelp(Table table) {
		return table.row(0).cellExists(1) && table.row(0).cell(1).text().equals("help");
	}

	private void finishAllTables(Tables tables, int from, TableListener tableListener) {
		int size = tables.size();

		for (int i = from; i < size; i++) {
			tableListener.tableFinished(tables.table(i));
		}

	}

	public void run(Tables tables, int from, TableListener tableListener) {
		doEvaluator.doNotTearDownAutomatically();

		RunningState childState = new RunningState();
		runTables(tables, from, tableListener, false, childState);

		finishAllTables(tables, from, tableListener);

		doEvaluator.tearDown(tables.table(0), tableListener.getTestResults());
	}

	public void setStopOnError(boolean stopOnError) {
		this.stopOnError = stopOnError;
	}

	public void setAbandon(boolean abandoned) {
		this.abandoned = abandoned;
	}
}
